/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2006-2008 Sun Microsystems, Inc.
 * Portions Copyright 2014-2016 ForgeRock AS.
 */
package org.opends.server.types;

import org.forgerock.opendj.ldap.ModificationType;

/**
 * This class defines a data structure for storing and interacting
 * with a modification that may be requested of an entry in the Directory Server.
 */
@org.opends.server.types.PublicAPI(
     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
     mayInstantiate=true,
     mayExtend=false,
     mayInvoke=true)
public final class Modification
{
  /** The attribute for this modification. */
  private Attribute attribute;
  /** The modification type for this modification. */
  private ModificationType modificationType;
  /**
   * Indicates whether this modification was generated by internal processing
   * and therefore should not be subject to no-user-modification and related checks.
   */
  private boolean isInternal;

  /**
   * Creates a new modification with the provided information.
   *
   * @param  modificationType  The modification type for this modification.
   * @param  attribute         The attribute for this modification.
   */
  public Modification(ModificationType modificationType, Attribute attribute)
  {
    this(modificationType, attribute, false);
  }

  /**
   * Creates a new modification with the provided information.
   *
   * @param  modificationType  The modification type for this modification.
   * @param  attribute         The attribute for this modification.
   * @param  isInternal        Indicates whether this is an internal modification
   *                           and therefore should not be subject to
   *                           no-user-modification and related checks.
   */
  public Modification(ModificationType modificationType, Attribute attribute, boolean isInternal)
  {
    this.modificationType = modificationType;
    this.attribute        = attribute;
    this.isInternal       = isInternal;
  }

  /**
   * Retrieves the modification type for this modification.
   *
   * @return  The modification type for this modification.
   */
  public ModificationType getModificationType()
  {
    return modificationType;
  }

  /**
   * Specifies the modification type for this modification.
   *
   * @param  modificationType  The modification type for this modification.
   */
  @org.opends.server.types.PublicAPI(
       stability=org.opends.server.types.StabilityLevel.PRIVATE,
       mayInstantiate=false,
       mayExtend=false,
       mayInvoke=false)
  public void setModificationType(ModificationType modificationType)
  {
    this.modificationType = modificationType;
  }

  /**
   * Retrieves the attribute for this modification.
   *
   * @return  The attribute for this modification.
   */
  public Attribute getAttribute()
  {
    return attribute;
  }

  /**
   * Specifies the attribute for this modification.
   *
   * @param  attribute  The attribute for this modification.
   */
  @org.opends.server.types.PublicAPI(
       stability=org.opends.server.types.StabilityLevel.PRIVATE,
       mayInstantiate=false,
       mayExtend=false,
       mayInvoke=false)
  public void setAttribute(Attribute attribute)
  {
    this.attribute = attribute;
  }

  /**
   * Indicates whether this is modification was created by internal processing
   * and should not be subject to no-user-modification and related checks.
   *
   * @return  {@code true} if this is an internal modification, or {@code false} if not.
   */
  public boolean isInternal()
  {
    return isInternal;
  }

  /**
   * Specifies whether this modification was created by internal processing
   * and should not be subject to no-user-modification and related checks.
   *
   * @param  isInternal  Specifies whether this modification was created
   *                     by internal processing and should not be subject to
   *                     no-user-modification and related checks.
   */
  public void setInternal(boolean isInternal)
  {
    this.isInternal = isInternal;
  }

  /**
   * Indicates whether the provided object is equal to this modification.
   * It will only be considered equal if the object is a modification
   * with the same modification type and an attribute that is equal to this modification.
   *
   * @param  o  The object for which to make the determination.
   * @return  {@code true} if the provided object is a
   *          modification that is equal to this modification,
   *          or {@code false} if not.
   */
  @Override
  public boolean equals(Object o)
  {
    if (this == o)
    {
      return true;
    }
    if (!(o instanceof Modification))
    {
      return false;
    }

    Modification m = (Modification) o;
    return modificationType == m.modificationType
        && attribute.equals(m.attribute);
  }

  /**
   * Retrieves the hash code for this modification.  The hash code
   * returned will be the hash code for the attribute included in this modification.
   *
   * @return  The hash code for this modification.
   */
  @Override
  public int hashCode()
  {
    return attribute.hashCode();
  }

  /**
   * Retrieves a one-line string representation of this modification.
   *
   * @return  A one-line string representation of this modification.
   */
  @Override
  public String toString()
  {
    StringBuilder buffer = new StringBuilder();
    toString(buffer);
    return buffer.toString();
  }

  /**
   * Appends a one-line representation of this modification to the provided buffer.
   *
   * @param  buffer  The buffer to which the information should be appended.
   */
  private void toString(StringBuilder buffer)
  {
    buffer.append("Modification(").append(modificationType).append(", ").append(attribute);
  }
}
